#include "depui/depui.h"

#define MXMODULE_FILESEL
#define MXMODULE_LIST

static void mx__fontsel_geometry(MX_FONTSEL * fsel)
{
	MXDEBUG_INVARIANT(MXOBJ(fsel));

	mx_defaultrect(&fsel->_ok, 0);
	mx_layout(&fsel->_ok, (MX_LAYOUT_X2 | MX_LAYOUT_Y2), fsel, 0, 0);
	mx_geometry(&fsel->_ok);

	mx_defaultrect(&fsel->_apply, 0);
	mx_layout(&fsel->_apply, (MX_LAYOUT_LEFT | MX_LAYOUT_Y1), &fsel->_ok, 1, 0);
	mx_geometry(&fsel->_apply);

	mx_defaultrect(&fsel->_load, 0);
	mx_layout(&fsel->_load, (MX_LAYOUT_LEFT | MX_LAYOUT_Y1), &fsel->_apply, 1, 0);
	mx_geometry(&fsel->_load);

	mx_position(&fsel->_fonts, 0, 0, mx_w(fsel), mx_y(&fsel->_ok) - 1);
	mx_geometry(&fsel->_fonts);
}

/** This function refreshes a font selector dialog with the currently
available fonts.  This function should be called after creating the font
selector and before it gets displayed or gets an MX_GEOMETRY event. */
void mx_fontsel_refresh(MX_FONTSEL * fsel)
{
	int i = 0;
	MX_GUIFONT *guifont = mx_guifont_index(i);

	MXDEBUG_INVARIANT(MXOBJ(fsel));

	mx_list_empty(&fsel->_fonts);

	while (guifont) {
		MX_LISTELEM *elem = mx_listelem((MX_LISTELEM *) 0, 0, &fsel->_fonts, i);
		const char *text = mx_guifont_text(guifont);

		mx_text_setcopy(elem, text, -1);

		++i;
		guifont = mx_guifont_index(i);
	}
	mx_geometry(&fsel->_fonts);
}

void mx_fontsel_handler(MX_WIN * win)
{
	MX_FONTSEL *fsel = (MX_FONTSEL *) win;

	MXDEBUG_INVARIANT(MXOBJ(win));
	MXDEBUG_INVARIANT(MXOBJ(mx.obj));

	if (mx_eventmatch(MX_GEOMETRY, fsel)) {
		mx__fontsel_geometry(fsel);

	} else if (mx_eventmatch(MX_DEFAULTRECT, fsel)) {
		MX_RECT *rrect = mx_defaultrect_data();

		rrect->x2 = rrect->x1 + 200;
		rrect->y2 = rrect->y1 + 120;
		return;

	} else if (mx_eventmatch(MX_LIST_CHANGED, &fsel->_fonts)) {
		int lindex = mx_list_selected_id(&fsel->_fonts);

		if (lindex >= 0) {
			fsel->_chosen = mx_guifont_index(lindex);
			mx_disable(&fsel->_ok, false);
			mx_disable(&fsel->_apply, false);
		} else {
			fsel->_chosen = 0;
			mx_disable(&fsel->_ok, true);
			mx_disable(&fsel->_apply, true);
		}

		mx_dirty(&fsel->_ok, true);
		mx_dirty(&fsel->_apply, true);
		return;

	} else if (mx_eventmatch(MX_SELECT, &fsel->_ok)) {
		if (fsel->_chosen) {
			const unsigned int ret = mx_inform(MX_FONTSEL_OK, fsel, sizeof(fsel));
			if ((!ret) && (fsel->_chosen))
				mx_guifont_default(fsel->_chosen);

			mx_delete(fsel);
			return;
		}

	} else if (mx_eventmatch(MX_SELECT, &fsel->_apply)) {
		if (fsel->_chosen) {
			const unsigned int ret = mx_inform(MX_FONTSEL_OK, fsel, sizeof(fsel));
			if ((!ret) && (fsel->_chosen))
				mx_guifont_default(fsel->_chosen);

			return;
		}

	} else if (mx_eventmatch(MX_SELECT, &fsel->_load)) {
		MX_FILESEL *sel = mx_fileselwin(0, 0, 0, MXID_FONTSELLOAD);
		const char *path = mx_platform_font_path();

		mx_text_set(sel, "Load font", -1, 0);

		if (!path)
			path = "./*.*";

		mx_filesel_path(sel, path, -1);
		mx_filesel_refresh(sel);

		mx_defaultrect(sel, 0);
		mx_layout(sel, MX_LAYOUT_CENTER, (MX_OBJ *) 0, 0, 0);
		mx_geometry(sel);

		mx_modal(sel);

		mx_win_dirty(sel);
		return;

	} else if (mx_eventmatch(MX_KEY_UNUSED, win)) {
		const MX_KEY_INFO *info = mx_key_info();

		if ((info) && (info->ascii == 0x1b)) {
			mx_win_dirty(fsel);
			mx_delete(fsel);
		}

	} else if (mx.event == MX_FILESEL_OK) {
		const char *path = mx_filesel_info(MXID_FONTSELLOAD);

		if (path) {
			MX_LISTELEM *ptr = 0;

			mx_guifont_load(path, path);
			mx_fontsel_refresh(fsel);

			/* Select the last loaded font. */
			ptr = mx_list_last(&fsel->_fonts);
			if (ptr)
				mx_select(ptr, true);

			mx_dirty(&fsel->_fonts, true);
		}
	}

	mx_win_handler(win);
}

MX_FONTSEL *mx_fontselwin(MX_FONTSEL * fsel, size_t size, MX_HANDLER handler, int theid)
{
	MXMINSIZE(size, MX_FONTSEL);

	if (!handler)
		handler = mx_fontsel_handler;

	fsel = (MX_FONTSEL *) mx_win(fsel, size, handler, theid);
	if (fsel) {
		MXDEBUG_ALLOCTAG(fsel);
		MXDEBUG_ATOMNAME(fsel, "fontsel");
		mx_text_set(fsel, "Choose font", -1, 0);

		mx_button(&fsel->_ok, 0, fsel, 0);
		mx_text_set(&fsel->_ok, "ok", -1, 0);
		mx_disable(&fsel->_ok, true);
		MXDEBUG_ATOMNAME(&fsel->_ok, "fontsel_ok");

		mx_button(&fsel->_apply, 0, fsel, 0);
		mx_text_set(&fsel->_apply, "apply", -1, 0);
		mx_disable(&fsel->_apply, true);
		MXDEBUG_ATOMNAME(&fsel->_apply, "fontsel_apply");

		mx_button(&fsel->_load, 0, fsel, 0);
		mx_text_set(&fsel->_load, "load", -1, 0);
		MXDEBUG_ATOMNAME(&fsel->_load, "fontsel_load");

		mx_list(&fsel->_fonts, 0, fsel, 0);
/**fix		mx_text_set(&fsel->_fonts, "fonts", -1, 0); */
		MXDEBUG_ATOMNAME(&fsel->_fonts, "fontsel_fonts");
	}

	MXDEBUG_INVARIANT(MXOBJ(fsel));
	return fsel;
}

/** !Font selection information
When a font has been chosen from a font selector dialog the a 
MX_FONTSEL_OK event is sent to the parent window.  This function can be called
when handling that event to determine the font selected. */
MX_GUIFONT *mx_fontsel_info(const int idnum)
{
	MX_FONTSEL *sel;

/** This function should only be called when handling an MX_FONTSEL_event. */
	assert(mx.event == MX_FONTSEL_OK);
	if (mx.event != MX_FONTSEL_OK)
		return 0;

	sel = (MX_FONTSEL *) mx.data;
	MXDEBUG_INVARIANT(MXOBJ(sel));

/** The sepcified id number has to match the one with the selected font. */
	if ((sel) && (MXID(sel) == idnum))
		return sel->_chosen;

	return 0;
}
